package com.google.code.stalkernet.node;

import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;

import com.google.code.stalkernet.advertisement.Advertisement;
import com.google.code.stalkernet.node.event.NodeEvent;
import com.google.code.stalkernet.node.event.NodeListener;
import com.google.code.stalkernet.peer.Peer;

/**
 * Abstract base class for implementations of {@link Node} interface.
 *
 * @author Mikhail Vladimirov
 */
public abstract class AbstractNode implements Node
{
    private final Collection <NodeListener> nodeListeners =
            new CopyOnWriteArrayList <> ();

    /**
     * {@inheritDoc}
     */
    @Override
    public void addNodeListener (NodeListener nodeListener)
    {
        if (nodeListener == null)
            throw new IllegalArgumentException ("Node listener is null");

        nodeListeners.add (nodeListener);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void removeNodeListener (NodeListener nodeListener)
    {
        if (nodeListener == null)
            throw new IllegalArgumentException ("Node listener is null");

        nodeListeners.remove (nodeListener);
    }

    /**
     * Get all registered node listeners.
     *
     * @return an array of {@link NodeListener} objects
     */
    public NodeListener [] getAllNodeListeners ()
    {
        return nodeListeners.toArray (new NodeListener [nodeListeners.size ()]);
    }

    /**
     * Notify all listeners about added peer.
     *
     * @param peer added peer
     */
    protected void firePeerAdded (Peer peer)
    {
        if (peer == null)
            throw new IllegalArgumentException ("Peer is null");

        NodeEvent nodeEvent = null;

        for (NodeListener nodeListener: nodeListeners)
        {
            if (nodeEvent == null)
                nodeEvent = new NodeEvent (this, peer);

            nodeListener.peerAdded (nodeEvent);
        }
    }

    /**
     * Notify all listeners about removed peer.
     *
     * @param peer removed peer
     */
    protected void firePeerRemoved (Peer peer)
    {
        if (peer == null)
            throw new IllegalArgumentException ("Peer is null");

        NodeEvent nodeEvent = null;

        for (NodeListener nodeListener: nodeListeners)
        {
            if (nodeEvent == null)
                nodeEvent = new NodeEvent (this, peer);

            nodeListener.peerRemoved (nodeEvent);
        }
    }

    /**
     * Notify all listeners about received advertisement.
     *
     * @param peer peer the advertisement was received from
     * @param advertisement received advertisement
     */
    protected void fireAdvertisementReceived (
        Peer peer, Advertisement advertisement)
    {
        if (peer == null)
            throw new IllegalArgumentException ("Peer is null");

        if (advertisement == null)
            throw new IllegalArgumentException ("Advertisement is null");

        NodeEvent nodeEvent = null;

        for (NodeListener nodeListener: nodeListeners)
        {
            if (nodeEvent == null)
                nodeEvent = new NodeEvent (this, peer, advertisement);

            nodeListener.advertisementReceived (nodeEvent);
        }
    }
}
